package org.ph.share.lock.test.thread2;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;

/**
 * 账户转账实践
 *
 * @author Hush.
 * @since 2023/5/17 20:13
 */
@Slf4j
public class TransferMoney {
    static Random random = new Random();

    public static int getRandomNum() {
        return random.nextInt(10) * 10;
    }

    @SneakyThrows
    public static void main(String[] args) {
        Account account1 = new Account(10000);
        Account account2 = new Account(10000);

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                account1.transfer(account2, getRandomNum());
            }

        }, "t1");
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                account2.transfer(account1, getRandomNum());
            }
        }, "t2");
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();

        log.info("money:{}", account2.getMoney() + account1.getMoney());

    }

}

/**
 * 账户类
 *
 * @author Hush.
 * @since 2023/5/17 20:14
 */
class Account {
    /**
     * 金额
     */
    private int money;

    /**
     * 模拟转账[线程不安全]
     *
     * @param target 目标账户
     * @param money  金额
     */
    public void transfer(Account target, int money) {
        if (this.money >= money) {
            target.setMoney(target.getMoney() + money);
            this.money -= money;
        }
    }

    /**
     * 模拟转账[线程安全]
     *
     * @param target 目标账户
     * @param money  金额
     */
    public void transfer2(Account target, int money) {
        synchronized (Account.class) {
            if (this.money >= money) {
                target.setMoney(target.getMoney() + money);
                this.money -= money;
            }
        }

    }

    public Account(int money) {
        this.money = money;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}
